/*!
\copyright  Copyright (c) 2023 Qualcomm Technologies International, Ltd.
            All Rights Reserved.
            Qualcomm Technologies International, Ltd. Confidential and Proprietary.
\file
\brief      Power on DSP ahead of time to save time later.

*/


#include "audio_startup.h"

#include <power_manager.h>
#include <domain_message.h>

#include <vmal.h>
#include <operators.h>
#include <logging.h>

#include <message.h>
#include <operator.h>


typedef enum
{
    AUDIO_STARTUP_INTERNAL_PROSPECTIVE_POWER_OFF = INTERNAL_MESSAGE_BASE,
} audio_startup_internal_msg_t;

typedef struct
{
    TaskData task_data;
    unsigned handled_async_prospective_dsp_power_on:1;
    unsigned handled_sync_prospective_dsp_power_on:1;
    unsigned async_dsp_power_on_in_progress:1;
} audio_startup_ctx_t;

static void audioStartup_AudioHasStartedCallback(bool exiting_lp_mode);
static void audioStartup_HandleOff(void);
static void audioStartup_MessageHandler(Task task, MessageId id, Message message);

static audio_startup_ctx_t ctx = {
        .task_data.handler = audioStartup_MessageHandler,
        .handled_async_prospective_dsp_power_on = FALSE,
        .handled_sync_prospective_dsp_power_on = FALSE,
        .async_dsp_power_on_in_progress = FALSE,
};

static const vmal_callbacks_t vmal_callbacks =
{
    .TurnedFrameworkOn = audioStartup_AudioHasStartedCallback,
};

static const vmal_registry_per_observer_t vmal_registration =
{
    .callbacks = &vmal_callbacks,
};

bool AudioStartup_Init(Task init_task)
{
    UNUSED(init_task);

    VmalRegisterAudioFrameworkObserver(&vmal_registration);

    return TRUE;
}

void AudioStartup_ProspectiveOn(audio_startup_mode_t mode)
{
    DEBUG_LOG_FN_ENTRY("AudioStartup_ProspectiveOn enum:audio_startup_mode_t:%d", mode);

    DEBUG_LOG("AudioStartup_ProspectiveOn handled_async_prospective_dsp_power_on %u handled_sync_prospective_dsp_power_on %u", ctx.handled_async_prospective_dsp_power_on, ctx.handled_sync_prospective_dsp_power_on);

    switch(mode)
    {
        case audio_startup_mode_async:
        {
            if(!ctx.handled_async_prospective_dsp_power_on && !ctx.handled_sync_prospective_dsp_power_on)
            {
                DEBUG_LOG("AudioStartup_ProspectiveOn executing asynchronous power on");
                appPowerPerformanceProfileRequest();
                if(VmalOperatorFrameworkEnableMainProcessorAsync())
                {
                    appPowerPerformanceProfileRelinquish();
                }
                else
                {
                    ctx.async_dsp_power_on_in_progress = TRUE;
                }
                ctx.handled_async_prospective_dsp_power_on = TRUE;
            }
        }
        break;

        case audio_startup_mode_immediate:
        {
            if(!ctx.handled_sync_prospective_dsp_power_on)
            {
                DEBUG_LOG("AudioStartup_ProspectiveOn executing synchronous power on");
                appPowerPerformanceProfileRequest();
                VmalOperatorFrameworkEnableMainProcessor();
                appPowerPerformanceProfileRelinquish();
                ctx.handled_sync_prospective_dsp_power_on = TRUE;
            }
        }
        break;

        default:
        {
            Panic();
        }
        break;
    }

    MessageCancelFirst((Task)&ctx.task_data, AUDIO_STARTUP_INTERNAL_PROSPECTIVE_POWER_OFF);
    MessageSendLater((Task)&ctx.task_data, AUDIO_STARTUP_INTERNAL_PROSPECTIVE_POWER_OFF, NULL,
            AudioStartup_ProspectiveAudioOffTimeout());
}

static void audioStartup_AudioHasStartedCallback(bool exiting_lp_mode)
{
    UNUSED(exiting_lp_mode);
    DEBUG_LOG("audioStartup_AudioHasStartedCallback was async dsp power on in progress %d", ctx.async_dsp_power_on_in_progress);

    if(ctx.async_dsp_power_on_in_progress)
    {
        ctx.async_dsp_power_on_in_progress = FALSE;

        appPowerPerformanceProfileRelinquish();
    }
    
}

/* Handle AUDIO_STARTUP_INTERNAL_PROSPECTIVE_POWER_OFF - switch off DSP again */
static void audioStartup_HandleOff(void)
{
    DEBUG_LOG_FN_ENTRY("audioStartup_HandleOff");

    if(ctx.handled_async_prospective_dsp_power_on)
    {
        OperatorsFrameworkDisable();
        ctx.handled_async_prospective_dsp_power_on = FALSE;
    }

    if(ctx.handled_sync_prospective_dsp_power_on)
    {
        OperatorsFrameworkDisable();
        ctx.handled_sync_prospective_dsp_power_on = FALSE;
    }
}

static void audioStartup_MessageHandler(Task task, MessageId id, Message message)
{
    UNUSED(task);
    UNUSED(message);

    switch(id)
    {
        case AUDIO_STARTUP_INTERNAL_PROSPECTIVE_POWER_OFF:
            audioStartup_HandleOff();
            break;

        default:
            break;
    }
}

